Skip to content

feat(skills): unify license-file naming and ship a license in every bundle - #47

Merged
UnbreakableMJ merged 1 commit into
mainfrom
license-naming-migration
Aug 22, 2026
Merged

feat(skills): unify license-file naming and ship a license in every bundle#47
UnbreakableMJ merged 1 commit into
mainfrom
license-naming-migration

Conversation

@UnbreakableMJ

Copy link
Copy Markdown
Contributor

Migrates the catalogue onto Standard §4.3 naming and §5.6 license carriage, both landed in v1.50 (Standard#29, Construct#46). Third and last PR of the series.

Before

  • 34 of 44 bundles shipped no license text at all — consumers install the .zip/.skill and never see the repo root
  • 9 skills carried LICENSE.md: markdown-converted GPL, in three non-identical variants, one of which (spacecraft-texinfo-document) was a hand-written prose page containing no license text
  • microsoft-rust-guidelines used the dash form LICENSE-GPL / LICENSE-MIT
  • The documented bundle recipe named <name>/LICENSE — matching none of the files that actually existed
  • ship.rs probed ["LICENSE", "LICENSE.md", "CREDITS.md"], so its rebuild hint dropped both license files from the one skill with a legal need for them

After

Count File License
43 LICENSE GPL-3.0-or-later
1 LICENSE GFDL-1.3-or-latergnu-coding-standards, third-party-derived (§4.2)
1 LICENSE.GPL + LICENSE.MIT microsoft-rust-guidelines, dual-licensed
1 LICENSE (flat bundle root) grok-skills/gfm-markdown

Every file is a regular file, byte-identical to the canonical text in LICENSES/, and present in both bundles. Which license applies is read from REUSE.toml, not a hand-kept list.

android-skills/ and orca-skills/ are untouched — §4.2 preserves upstream layout verbatim, including upstream's own LICENSE.txt. Confirmed by diff: no staged path under either tree.

The gate

New .github/check-license-files.py, wired into CI. It verifies §4.3 naming, regular-file-ness, byte-equality against LICENSES/, and actual presence inside both bundles.

A gate that cannot fail is worthless, so it was negative-tested against six violation classes — all six caught:

Injected violation Caught as
LICENSE deleted missing LICENSE (§5.6 license carriage; skill is GPL-3.0-or-later)
LICENSE made a symlink is a symlink; §5.6 requires a regular file
one trailing byte added not byte-identical to LICENSES/GPL-3.0-or-later.txt (§5.6)
stray LICENSE.md non-compliant license filename (§4.3)
dash form LICENSE-MIT missing LICENSE.MIT
bundle rebuilt without the license does not ship spacecraft-lua-guidelines/LICENSE (§5.6)

Also

  • Root COPYING symlink → LICENSE (§4.3 GNU convention). Verified: git stores it mode 120000, reuse lint ignores it, and licensee still resolves the regular LICENSE at exact/100.
  • ship.rs: candidate list becomes a documented BUNDLE_FILES const covering LICENSE and the LICENSE.<TAG> forms.
  • The texinfo prose page wasn't just deleted. Its one substantive non-boilerplate fact — that the skill's own license is independent of the license of the manuals it produces — moved into its SKILL.md.
  • Docs corrected: AGENTS.md, CONTRIBUTING.md, README.md, grok-skills/README.md, and microsoft-rust-guidelines' SKILL.md / CREDITS.md links, which pointed at the pre-rename filenames.

Verification

Run against a clean git archive HEAD checkout so gitignored local files can't mask a failure:

Gate Result
license files (§4.3 naming, §5.6 carriage) PASS
skill cross-references + version pins PASS
steelbore.scm matches steelbore.toml PASS
reuse lint PASS
SKILL.md description cap PASS
bundle drift sweep (content + missing) across all 45 no DRIFT lines
cargo fmt --check / clippy -D warnings / cargo test PASS
GitHub license detection GPL-3.0, exact, 100
commit signature / timezone %G? = G, +0000

Note on staging

The repo rule is never git add -A, because other root .skill files can carry pre-existing uncommitted changes. Here every bundle legitimately changes, so I staged in bulk with .gitignore excluded — then audited the staged set by category (45 .zip, 45 .skill, 46 license files, 13 named others) and confirmed nothing from target/, Chat*, Excluded/, or the vendored trees was swept in. The working tree was clean apart from .gitignore before this branch, which is what makes that safe; it is not a precedent for ordinary single-skill edits.

After merge

~/.claude/skills/ and the other per-harness paths refresh only after a Home Manager rebuild — maintainer-run, not automated. construct skill sync in consumer flakes afterwards.

…undle

Migrates the catalogue onto Standard §4.3 naming and §5.6 license carriage
(both landed in v1.50 — Standard#29, Construct#46).

Before: 34 of 44 bundles shipped no license text at all. Nine skills carried
LICENSE.md — markdown-converted GPL, in three non-identical variants, one of
which (spacecraft-texinfo-document) was a hand-written prose page containing
no license text. microsoft-rust-guidelines used the dash form LICENSE-GPL /
LICENSE-MIT. The documented bundle recipe named <name>/LICENSE, which matched
none of the files that actually existed.

After: every one of the 44 shipped skills plus the Grok skill carries a
license file named per §4.3, a regular file, byte-identical to the canonical
text in LICENSES/, and present in both bundles.

  43 x LICENSE                      GPL-3.0-or-later
   1 x LICENSE                      GFDL-1.3-or-later (gnu-coding-standards,
                                    third-party-derived per §4.2)
   1 x LICENSE.GPL + LICENSE.MIT    microsoft-rust-guidelines, dual-licensed
   1 x LICENSE (flat bundle root)   grok-skills/gfm-markdown

Which license applies is read from REUSE.toml rather than a hand-kept list.
android-skills/ and orca-skills/ are untouched: §4.2 preserves upstream
layout verbatim, including upstream's own LICENSE.txt.

Adds .github/check-license-files.py and wires it into CI. It verifies naming,
regular-file-ness, byte-equality against LICENSES/, and actual presence inside
both bundles. Negative-tested against six violation classes — missing file,
symlink, one byte of drift, stray LICENSE.md, dash-form LICENSE-MIT, and a
bundle built without the license — each of which it catches.

Adds a root COPYING symlink to LICENSE (§4.3 GNU convention). reuse ignores
it and GitHub's detector still resolves the regular LICENSE at rank 1.00.

ship.rs: the rebuild-hint candidate list becomes a documented BUNDLE_FILES
const covering LICENSE and the LICENSE.<TAG> forms. It previously probed
LICENSE.md and would have dropped microsoft-rust-guidelines' two license
files from the hint — the one skill with a legal need for both.

The texinfo skill's LICENSE.md carried one substantive fact beyond boilerplate
— that the skill's own license is independent of the license of the manuals it
produces — which is preserved in its SKILL.md rather than lost with the file.

Docs updated to match: AGENTS.md, CONTRIBUTING.md, README.md,
grok-skills/README.md, and microsoft-rust-guidelines' SKILL.md / CREDITS.md
links, which pointed at the pre-rename filenames.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SmZmsWzmSaXpS7bFQu3fWJ
@UnbreakableMJ
UnbreakableMJ merged commit 8b20eee into main Aug 22, 2026
3 checks passed
@UnbreakableMJ
UnbreakableMJ deleted the license-naming-migration branch August 22, 2026 10:03

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3d981569e6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +63 to +64
skills = [(p.parent, p.parent.name) for p in sorted(repo.glob("*/SKILL.md"))
if (repo / f"{p.parent.name}.zip").exists()]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Check new skills even before their bundles exist

When a new top-level skill is added without <name>.zip, this filter omits it entirely, so the gate reports success instead of detecting the missing license and both missing bundles. This matters because flake.nix auto-detects every top-level directory containing SKILL.md and can therefore distribute that unlicensed skill source despite CI passing; enumerate all non-vendored skill directories and let the later bundle-existence checks report omissions.

AGENTS.md reference: AGENTS.md:L413-L420

Useful? React with 👍 / 👎.

Comment on lines +108 to +109
if entry not in names:
problems.append(f"{name}{ext}: does not ship {entry} (§5.6)")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate the license bytes stored in each bundle

If a bundle contains the expected license entry but its contents are stale or corrupted, this check passes because it only tests the entry name; for example, replacing spacecraft-lua-guidelines/LICENSE inside its zip with arbitrary bytes still yields zero license-file problems. Since neither this workflow nor construct skill ship otherwise compares bundle contents, a license-file update can reach consumers with the previous text unless zf.read(entry) is compared with the canonical or working-tree bytes.

AGENTS.md reference: AGENTS.md:L423-L426

Useful? React with 👍 / 👎.

UnbreakableMJ added a commit that referenced this pull request Aug 24, 2026
PR #45 edited spacecraft-cli-preference/SKILL.md and references/jaq.md without
rebuilding the two bundles that are the install surface, so every consumer
installing from the zip would still get the old "near drop-in" claim and the
wrong slurp example.

Rebuilt both from the rebased branch, so they also carry the LICENSE file that
landed in #47.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M94JK8t6zguGCTDP7udiUv
UnbreakableMJ added a commit that referenced this pull request Aug 24, 2026
* cli-preference: jaq is not a drop-in for jq

The reference's Gotchas said only that "a handful of exotic jq features aren't
supported" and that `--stream` is missing. Measured against jq 1.8.1 that is a
serious understatement, and the page was recommending a command that silently
does the wrong thing.

The substantive gap is auto-vivification: jq creates missing containers along an
assignment path and jaq does not, so `echo null | jaq '.a.b = 1'` errors where
jq returns {"a":{"b":1}}. Every "build the object as you go" idiom breaks.

Example 6 was `jaq -s 'add' a.json b.json`. jaq slurps per file and runs the
filter once per input, so that command prints two results where the reader
plainly expects one. Corrected to a single file with the divergence called out.

Also records: output-format flags are not last-wins under jaq, 22 jq builtins
are missing, 9 jq flags are rejected, and the arithmetic corners. Adds the
warning that jaq has `-i/--in-place` where jq does not, so an unrecognised flag
must never be passed through blindly.

Points at Pathfinder for the case where existing jq scripts have to keep
working, and marks the §3 mapping-table row as not alias-safe.

The SKILL.md frontmatter description is untouched and remains 986 characters,
within the §5.6 cap.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011r8wNFByLqoc2ZWevWUUMu

* chore(cli-preference): rebuild bundles for the jaq compatibility rewrite

PR #45 edited spacecraft-cli-preference/SKILL.md and references/jaq.md without
rebuilding the two bundles that are the install surface, so every consumer
installing from the zip would still get the old "near drop-in" claim and the
wrong slurp example.

Rebuilt both from the rebased branch, so they also carry the LICENSE file that
landed in #47.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M94JK8t6zguGCTDP7udiUv

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant